package com.aplink.generic.adapter;

import java.lang.ref.WeakReference;
import java.util.ArrayList;

import uk.co.senab.photoview.PhotoView;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v4.view.PagerAdapter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;

import com.aplink.generic.GenericApplication;
import com.aplink.generic.cache.BitmapCacheDisk;
import com.aplink.generic.network.GenericFile;
import com.aplink.generic.pojo.ContentData;
import com.aplink.generic.pojo.GenericObject;
import com.aplink.generic.pojo.ObjPropInfo;
import com.aplink.generic.pojo.controlspec.GallerySpec;
import com.aplink.sg.R;

public class GalleryPagerAdapter extends PagerAdapter {
	private ContentData mContentData;
	private ArrayList<GenericObject> mDisplayObjects;
	private final GallerySpec mGallerySpec;
	private ArrayList<GenericObject> mOriginalObjects;
	private BitmapCacheDisk mDiskCache;

	@SuppressWarnings("unchecked")
	public GalleryPagerAdapter(final ArrayList<GenericObject> genericObjects,
			final GallerySpec gallerySpec) {
		this.mOriginalObjects = genericObjects;
		this.mDisplayObjects = (ArrayList<GenericObject>) genericObjects
				.clone();
		this.mGallerySpec = gallerySpec;
		mContentData = gallerySpec.getContentData();
		mDiskCache = new BitmapCacheDisk("BitmapCache", GenericApplication
				.getInstance().getApplicationContext());
	}

	public GenericObject add(final String imageURL) {
		final GenericObject genericObject = new GenericObject();
		genericObject.put(this.mGallerySpec.getImagePathColumn(), imageURL);
		final String createdTime = GenericApplication.getInstance()
				.getCreatedTime();
		for (ObjPropInfo createdTimeCol : mContentData.getCreatedTimeObject()) {
			genericObject.put(createdTimeCol.getFullColumnName(), createdTime);
		}
		this.mOriginalObjects.add(genericObject);
		this.mDisplayObjects.add(genericObject);
		notifyDataSetChanged();
		return genericObject;
	}

	public GenericObject delete(final int position) {
		if (position >= mDisplayObjects.size()) {
			return null;
		}
		final GenericObject genericObject = this.mDisplayObjects.get(position)
				.clone();
		this.mDisplayObjects.remove(position);
		notifyDataSetChanged();
		return genericObject;
	}

	@Override
	public int getCount() {
		return this.mDisplayObjects.size();
	}

	public final ArrayList<GenericObject> getDisplayObjects() {
		return mDisplayObjects;
	}

	public GenericFile getFile(final GenericObject genericObject) {
		final GenericFile genericFile = new GenericFile();
		final String localPath = genericObject.getValue(this.mGallerySpec
				.getImagePathColumn());
		genericFile.setLocalPath(localPath);
		genericFile.setFileNameByURl(localPath);
		return genericFile;
	}

	public Filter getFilter(final ArrayList<String> searchFileds) {
		final Filterable filterable = new Filterable() {

			@Override
			public Filter getFilter() {
				return new ViewPagerFilter(searchFileds,
						GalleryPagerAdapter.this);
			}
		};

		return filterable.getFilter();
	}

	public ArrayList<GenericObject> getGenericObjects() {
		return this.mOriginalObjects;
	}

	@Override
	public View instantiateItem(ViewGroup container, int position) {
		final LayoutInflater vi = (LayoutInflater) container.getContext()
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		FrameLayout frameLayout = (FrameLayout) vi.inflate(
				R.layout.aplink__generic_photoview, container, false);
		PhotoView photoView = (PhotoView) frameLayout
				.findViewById(R.id.imageview);
		final GenericObject genericObject = this.mDisplayObjects.get(position);
		final String imagePath = genericObject.getValue(this.mGallerySpec
				.getImagePathColumn());
		TextView textView = (TextView) frameLayout
				.findViewById(R.id.textview_position);
		textView.setText((position + 1) + " / " + mDisplayObjects.size());
		container.addView(frameLayout, LayoutParams.MATCH_PARENT,
				LayoutParams.MATCH_PARENT);
		new Task(photoView).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
				imagePath);
		return frameLayout;
	}

	private class Task extends AsyncTask<String, Void, Bitmap> {
		private WeakReference<ImageView> mImageView;

		public Task(ImageView imageView) {
			mImageView = new WeakReference<ImageView>(imageView);
		}

		@Override
		protected Bitmap doInBackground(String... params) {
			Bitmap bitmap = mDiskCache.get(params[0].hashCode() + "");
			if (bitmap == null) {
				bitmap = decodeSampledBitmapFromFile(params[0],
						mGallerySpec.getImageWidth(),
						mGallerySpec.getImageHeight());
				mDiskCache.add(params[0].hashCode() + "", bitmap);
				mDiskCache.flush();
				Log.v("nglehien", "Decode");
			} else {
				Log.v("nglehien", "GetFromCache");
			}
			return bitmap;
		}

		@Override
		protected void onPostExecute(Bitmap result) {
			super.onPostExecute(result);
			if (mImageView.get() != null) {
				mImageView.get().setImageBitmap(result);
			}
		}
	}

	public static Bitmap decodeSampledBitmapFromFile(String filename,
			int reqWidth, int reqHeight) {

		// First decode with inJustDecodeBounds=true to check dimensions
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(filename, options);

		// Calculate inSampleSize
		options.inSampleSize = calculateInSampleSize(options, reqWidth,
				reqHeight);
		// Decode bitmap with inSampleSize set
		options.inJustDecodeBounds = false;
		return BitmapFactory.decodeFile(filename, options);
	}

	public static int calculateInSampleSize(BitmapFactory.Options options,
			int reqWidth, int reqHeight) {
		// BEGIN_INCLUDE (calculate_sample_size)
		// Raw height and width of image
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;

		if (height > reqHeight || width > reqWidth) {

			final int halfHeight = height / 2;
			final int halfWidth = width / 2;

			// Calculate the largest inSampleSize value that is a power of 2 and
			// keeps both
			// height and width larger than the requested height and width.
			while ((halfHeight / inSampleSize) > reqHeight
					&& (halfWidth / inSampleSize) > reqWidth) {
				inSampleSize *= 2;
			}

			// This offers some additional logic in case the image has a strange
			// aspect ratio. For example, a panorama may have a much larger
			// width than height. In these cases the total pixels might still
			// end up being too large to fit comfortably in memory, so we should
			// be more aggressive with sample down the image (=larger
			// inSampleSize).

			long totalPixels = width * height / inSampleSize;

			// Anything more than 2x the requested pixels we'll sample down
			// further
			final long totalReqPixelsCap = reqWidth * reqHeight * 2;

			while (totalPixels > totalReqPixelsCap) {
				inSampleSize *= 2;
				totalPixels /= 2;
			}
		}
		return inSampleSize;
		// END_INCLUDE (calculate_sample_size)
	}

	@Override
	public int getItemPosition(final Object object) {
		return PagerAdapter.POSITION_NONE;
	}

	public final ArrayList<GenericObject> getOriginalObjects() {
		return mOriginalObjects;
	}

	public final void setDisplayObjects(ArrayList<GenericObject> displayObjects) {
		mDisplayObjects = displayObjects;
	}

	public void setGenericObjects(final ArrayList<GenericObject> genericObjects) {
		this.mOriginalObjects = genericObjects;
	}

	public final void setOriginalObjects(
			ArrayList<GenericObject> originalObjects) {
		mOriginalObjects = originalObjects;
	}

	@Override
	public void destroyItem(ViewGroup container, int position, Object object) {
		container.removeView((View) object);
	}

	@Override
	public boolean isViewFromObject(View view, Object object) {
		return view == object;
	}

}
